// 用于拼接字符串（自动插入换行）并替换到代码文件的类
function myString(dfText) {
  this.val = dfText || "";
  this.add = (text) => (this.val += (text || "") + "\r\n");
  this.writeTo = (strCode, tag) => {
    return strCode.replace(new RegExp(`\\@${tag},?`, "g"), this.val.trimLeft());
  };
}

export const generatorService = (setting, temp, table) => {
  let strCode = temp;
  temp = null;

  if (setting.namespace.ibll != "learun.iapplication") {
    strCode = strCode.replace("@IBLLNamespace", `using ${setting.namespace.ibll}`);
  } else {
    strCode = strCode.replace("@IBLLNamespace", "");
  }

  strCode = strCode.replace("@Namespace", setting.namespace.service);
  strCode = strCode.replace("@ProjectName", `${setting.project.f_Name}-${setting.moduleName}`);
  strCode = strCode.replace("@CompanyName", setting.company);
  strCode = strCode.replace("@CreateUserName", setting.userInfo.f_RealName);
  strCode = strCode.replace("@Datetime", setting.createTime);

  strCode = strCode.replace("@ClassName", window.$upFirst(`${table.className}Service`));

  // 本身查询
  let queryCode = new myString();
  queryCode.add(`            var expression = LinqExtensions.True<${window.$upFirst(table.className)}Entity>();`);
  table.columns.forEach((column) => {
    const qname = window.$upFirst(column.name);
    if (
      ["string"].includes(column.csType) &&
      column.queryType == "1" &&
      table.field != column.name &&
      !column.isPrimary
    ) {
      queryCode.add(`            if(!string.IsNullOrEmpty(queryParams.${qname}))`);
      queryCode.add(`            {`);
      queryCode.add(`                expression = expression.And(t => t.${qname}.Contains(queryParams.${qname}));`);
      queryCode.add(`            }`);
    } else if (["DateTime"].includes(column.csType)) {
      queryCode.add(`            if(!string.IsNullOrEmpty(queryParams.${qname}QRange))`);
      queryCode.add(`            {`);
      queryCode.add(
        `                var ${window.$lowerFirst(column.name)}_list = queryParams.${qname}QRange.Split(',');`
      );
      queryCode.add(
        `                ${column.csType} ${window.$lowerFirst(column.name)} = Convert.ToDateTime(${window.$lowerFirst(
          column.name
        )}_list[0]);`
      );
      queryCode.add(
        `                ${column.csType} ${window.$lowerFirst(
          column.name
        )}_end = Convert.ToDateTime(${window.$lowerFirst(column.name)}_list[1]);`
      );
      queryCode.add(
        `                expression = expression.And(t => t.${qname} >= ${window.$lowerFirst(
          column.name
        )} &&t.${qname} <= ${window.$lowerFirst(column.name)}_end);`
      );
      queryCode.add(`            }`);
    } else if (!column.isPrimary) {
      if (["string"].includes(column.csType)) {
        queryCode.add(`            if(!string.IsNullOrEmpty(queryParams.${qname}))`);
      } else {
        queryCode.add(`            if(queryParams.${qname} != null)`);
      }
      queryCode.add(`            {`);
      queryCode.add(`                expression = expression.And(t => t.${qname} == queryParams.${qname});`);
      queryCode.add(`            }`);
    }
  });

  strCode = queryCode.writeTo(strCode, "QueryContent");
  queryCode = null;

  // 列表查询
  strCode = strCode.replace(
    "@FindListContent",
    `return this.BaseRepository(@DBCode).FindList<@MainTableEntity>(expression);`
  );
  // 分页查询
  strCode = strCode.replace(
    "@FindListPaginationContent",
    `return this.BaseRepository(@DBCode).FindList<@MainTableEntity>(expression,pagination);`
  );

  // 如果是主表，且有一对一的关系
  let tableMethod = new myString();
  let SAVELIST = new myString();
  if (table.type == "main" && setting.qTables.length > 1) {
    tableMethod.add(`        /// <summary>`);
    tableMethod.add(`        /// 获取@Des的列表数据`);
    tableMethod.add(`        /// <summary>`);
    tableMethod.add(`        /// <param name="queryParams">查询参数</param>`);
    tableMethod.add(`        /// <returns></returns>`);

    tableMethod.add(`        public Task<IEnumerable<@MainTableEntity>> GetRelateList(@MainTableEntity queryParams)`);
    tableMethod.add(`        {`);
    tableMethod.add(`            var strSql = GetQuerySql(queryParams);`);
    tableMethod.add(`            @FindListContent`);
    tableMethod.add(`        }`);

    tableMethod.add(`        /// <summary>`);
    tableMethod.add(`        /// 获取@Des的分页数据`);
    tableMethod.add(`        /// <summary>`);
    tableMethod.add(`        /// <param name="pagination">分页参数</param>`);
    tableMethod.add(`        /// <param name="queryParams">查询参数</param>`);
    tableMethod.add(`        /// <returns></returns>`);

    tableMethod.add(
      `        public Task<IEnumerable<@MainTableEntity>> GetRelatePageList(Pagination pagination, @MainTableEntity queryParams)`
    );
    tableMethod.add(`        {`);
    tableMethod.add(`            var strSql = GetQuerySql(queryParams);`);
    tableMethod.add(`            @FindListPaginationContent`);
    tableMethod.add(`        }`);

    tableMethod.add(`        private string GetQuerySql(@MainTableEntity queryParams)`);
    tableMethod.add(`        {`);
    tableMethod.add(`            @QueryContent`);
    tableMethod.add(`        }`);

    strCode = tableMethod.writeTo(strCode, "TableMethod");
    tableMethod = null;

    queryCode = new myString();

    queryCode.add(`            var strSql = new StringBuilder();`);
    queryCode.add(`            strSql.Append(@"SELECT @MainTableSQL            ");`);
    queryCode.add(`            strSql.Append(" where 1 = 1 ");`);
    queryCode.add(`            @MainQuerySetting`);
    queryCode.add(`            return strSql.ToString();`);
    strCode = queryCode.writeTo(strCode, "QueryContent");
    queryCode = null;

    // 列表查询
    strCode = strCode.replace(
      "@FindListContent",
      `return this.BaseRepository(@DBCode).FindList<@MainTableEntity>(strSql.ToString(),queryParams);`
    );
    // 分页查询
    strCode = strCode.replace(
      "@FindListPaginationContent",
      `return this.BaseRepository(@DBCode).FindList<@MainTableEntity>(strSql.ToString(),queryParams,pagination);`
    );

    let fieldCode = new myString();
    let mainTableSQLCode = new myString();
    let mainQuerySettingCode = new myString();
    setting.qTables.forEach((qTable) => {
      qTable.table.columns.forEach((column) => {
        let qfieldName = "";
        if (qTable.table.type == "main") {
          qfieldName = window.$upFirst(column.name);
          fieldCode.add(`            ${qTable.alias}.${column.name},`);
        } else {
          qfieldName = `${window.$upFirst(qTable.table.className)}_${window.$upFirst(column.name)}`;
          fieldCode.add(
            `            ${qTable.alias}.${column.name} as ${window.$upFirst(qTable.table.className)}_${window.$upFirst(
              column.name
            )},`
          );
        }

        if (["string"].includes(column.csType) && column.queryType == "1" && !column.isPrimary) {
          mainQuerySettingCode.add(`            if(!string.IsNullOrEmpty(queryParams.${qfieldName}))`);
          mainQuerySettingCode.add(`            {`);
          mainQuerySettingCode.add(
            `                strSql.Append(" AND ${qTable.alias}.${column.name} like %@${qfieldName}% ");`
          );
          mainQuerySettingCode.add(`            }`);
        } else if (["DateTime"].includes(column.csType)) {
          mainQuerySettingCode.add(`            if(!string.IsNullOrEmpty(queryParams.${qfieldName}QRange))`);
          mainQuerySettingCode.add(`            {`);

          mainQuerySettingCode.add(
            `                var ${window.$lowerFirst(qfieldName)}_list = queryParams.${qfieldName}QRange.Split(',');`
          );
          mainQuerySettingCode.add(
            `                ${column.csType} ${window.$lowerFirst(
              qfieldName
            )} = Convert.ToDateTime(${window.$lowerFirst(qfieldName)}_list[0]);`
          );
          mainQuerySettingCode.add(
            `                ${column.csType} ${window.$lowerFirst(
              qfieldName
            )}_end = Convert.ToDateTime(${window.$lowerFirst(qfieldName)}_list[1]);`
          );

          mainQuerySettingCode.add(
            `                strSql.Append($" AND ( ${qTable.alias}.${column.name} >= '{${window.$lowerFirst(
              qfieldName
            )}}' AND ${qTable.alias}.${column.name} <= '{${window.$lowerFirst(qfieldName)}_end}' )");`
          );
          mainQuerySettingCode.add(`            }`);
        } else if (!column.isPrimary) {
          if (["string"].includes(column.csType)) {
            mainQuerySettingCode.add(`            if(!string.IsNullOrEmpty(queryParams.${qfieldName}))`);
          } else {
            mainQuerySettingCode.add(`            if(queryParams.${qfieldName} != null)`);
          }

          mainQuerySettingCode.add(`            {`);
          mainQuerySettingCode.add(
            `                strSql.Append(" AND ${qTable.alias}.${column.name} = @${qfieldName} ");`
          );
          mainQuerySettingCode.add(`            }`);
        }
      });
      if (qTable.table.type == "main") {
        mainTableSQLCode.add(` ${qTable.table.name} ${qTable.alias}`);
      } else {
        mainTableSQLCode.add(
          `            LEFT JOIN ${qTable.table.name} ${qTable.alias} ON ${qTable.alias}.${qTable.table.field} = t.${qTable.table.relationField}`
        );
      }
    });
    mainTableSQLCode.val = `${fieldCode.val.slice(0, fieldCode.val.length - 3)} FROM ${mainTableSQLCode.val}`;
    fieldCode = null;
    strCode = mainTableSQLCode.writeTo(strCode, "MainTableSQL");
    mainTableSQLCode = null;
    strCode = mainQuerySettingCode.writeTo(strCode, "MainQuerySetting");
    mainQuerySettingCode = null;
  } else {
    if (table.relationType == "1") {
      tableMethod.add(`        /// <summary>`);
      tableMethod.add(`        /// 获取@Des的实体根据外键`);
      tableMethod.add(`        /// <summary>`);
      tableMethod.add(`        /// <param name="key">关联键</param>`);
      tableMethod.add(`        /// <returns></returns>`);
      tableMethod.add(`        public Task<@MainTableEntity> GetRelateEntity(string key) {`);
      tableMethod.add(
        `            return this.BaseRepository(@DBCode).FindEntity<@MainTableEntity>(t=>t.${window.$upFirst(
          table.field
        )} == key);`
      );
      tableMethod.add(`        }`);
    } else if (table.relationType == "2") {
      SAVELIST.add(`        /// <summary>`);
      SAVELIST.add(`        /// 保存子表数据`);
      SAVELIST.add(`        /// <summary>`);
      SAVELIST.add(`        /// <param name="key">外键值</param>`);
      SAVELIST.add(`        /// <param name="list">数据集合</param>`);
      SAVELIST.add(`        /// <returns></returns>`);
      SAVELIST.add(`        public async Task SaveList(string key, IEnumerable<@MainTableEntity> list) {`);
      SAVELIST.add(`            var addList = new List<@MainTableEntity>();`);
      SAVELIST.add(`            var db = this.BaseRepository().BeginTrans();`);
      SAVELIST.add(`            try{`);
      SAVELIST.add(`                await db.Delete<@MainTableEntity>(t => t.${window.$upFirst(table.field)} == key);`);
      SAVELIST.add(`                foreach (var item in list)`);
      SAVELIST.add(`                {`);

      const myMainKey = table.columns.find((t) => t.isPrimary);

      if (myMainKey.csType == "string") {
        SAVELIST.add(`                    if(string.IsNullOrEmpty(item.${window.$upFirst(myMainKey.name)}))`);
        SAVELIST.add(`                    {`);
        table.columns.forEach((col) => {
          if (col.dataType == "createId") {
            SAVELIST.add(`                        item.${window.$upFirst(col.name)} = this.GetUserId();`);
          }
          if (col.dataType == "createName") {
            SAVELIST.add(`                        item.${window.$upFirst(col.name)} = this.GetUserName();`);
          }
          if (col.dataType == "createTime") {
            SAVELIST.add(`                        item.${window.$upFirst(col.name)} = DateTime.Now;`);
          }
        });
        SAVELIST.add(`                        item.${window.$upFirst(myMainKey.name)} = Guid.NewGuid().ToString();`);
        SAVELIST.add(`                    }`);
      } else if (
        mainKey.csType == "int" &&
        table.columns.findIndex((t) => ["createId", "createName", "createTime"].includes(t.dataType)) > -1
      ) {
        SAVELIST.add(`                    if(item.${window.$upFirst(mainKey.name)} != null)`);
        SAVELIST.add(`                    {`);
        table.columns.forEach((col) => {
          if (col.dataType == "createId") {
            SAVELIST.add(`                        item.${window.$upFirst(col.name)} = this.GetUserId();`);
          }
          if (col.dataType == "createName") {
            SAVELIST.add(`                        item.${window.$upFirst(col.name)} = this.GetUserName();`);
          }
          if (col.dataType == "createTime") {
            SAVELIST.add(`                        item.${window.$upFirst(col.name)} = DateTime.Now;`);
          }
        });
        SAVELIST.add(`                    }`);
      }
      if (table.columns.findIndex((t) => ["modifyId", "modifyName", "modifyTime"].includes(t.dataType)) > -1) {
        SAVELIST.add(`                    else {`);
        table.columns.forEach((col) => {
          if (col.dataType == "modifyId") {
            SAVELIST.add(`                        item.${window.$upFirst(col.name)} = this.GetUserId();`);
          }
          if (col.dataType == "modifyName") {
            SAVELIST.add(`                        item.${window.$upFirst(col.name)} = this.GetUserName();`);
          }
          if (col.dataType == "modifyTime") {
            SAVELIST.add(`                        item.${window.$upFirst(col.name)} = DateTime.Now;`);
          }
        });
        SAVELIST.add(`                    }`);
      }

      SAVELIST.add(`                    item.${window.$upFirst(table.field)} = key;`);
      SAVELIST.add(`                    addList.Add(item);`);
      SAVELIST.add(`                }`);
      SAVELIST.add(`                if (addList.Count > 0)`);
      SAVELIST.add(`                {`);
      SAVELIST.add(`                    await db.Inserts(addList);`);
      SAVELIST.add(`                }`);
      SAVELIST.add(`                db.Commit();`);
      SAVELIST.add(`            }`);
      SAVELIST.add(`            catch (Exception)`);
      SAVELIST.add(`            {`);
      SAVELIST.add(`                db.Rollback();`);
      SAVELIST.add(`                throw;`);
      SAVELIST.add(`            }`);
      SAVELIST.add(`        }`);
    }

    strCode = tableMethod.writeTo(strCode, "TableMethod");
    tableMethod = null;
  }

  strCode = SAVELIST.writeTo(strCode, "SAVELIST");
  SAVELIST = null;

  let deleteMethod = new myString();

  if (table.type != "main") {
    deleteMethod.add(`        /// <summary>`);
    deleteMethod.add(`        /// 删除@Des的数据根据外键`);
    deleteMethod.add(`        /// <summary>`);
    deleteMethod.add(`        /// <param name="key">关联键</param>`);
    deleteMethod.add(`        /// <returns></returns>`);
    deleteMethod.add(`        public async Task DeleteRelate(string key) {`);
    deleteMethod.add(
      `            await this.BaseRepository(@DBCode).Delete<@MainTableEntity>(t=>t.${table.field} == key);`
    );
    deleteMethod.add(`        }`);
  }

  strCode = deleteMethod.writeTo(strCode, "DeleteMethod");
  deleteMethod = null;

  let pkCsType = table.columns.find((t) => t.isPrimary).csType;
  let pkIsNull = "";
  if (!["string"].includes(pkCsType)) {
    pkCsType += "?";

    pkIsNull = " keyValue != null ";
  } else {
    pkIsNull = " string.IsNullOrEmpty(keyValue) ";
  }

  let insertMethod = new myString();
  let updateMethod = new myString();

  const mainKey = table.columns.find((t) => t.isPrimary);

  if (mainKey) {
    if (mainKey.csType == "string") {
      insertMethod.add(`                if(string.IsNullOrEmpty(entity.${window.$upFirst(mainKey.name)}))`);
      insertMethod.add(`                {`);
      table.columns.forEach((col) => {
        if (col.dataType == "createId") {
          insertMethod.add(`                    entity.${window.$upFirst(col.name)} = this.GetUserId();`);
        }
        if (col.dataType == "createName") {
          insertMethod.add(`                    entity.${window.$upFirst(col.name)} = this.GetUserName();`);
        }
        if (col.dataType == "createTime") {
          insertMethod.add(`                    entity.${window.$upFirst(col.name)} = DateTime.Now;`);
        }
      });
      insertMethod.add(`                    entity.${window.$upFirst(mainKey.name)} = Guid.NewGuid().ToString();`);
      insertMethod.add(`                }`);
    } else if (
      mainKey.csType == "int" &&
      table.columns.findIndex((t) => ["createId", "createName", "createTime"].includes(t.dataType)) > -1
    ) {
      insertMethod.add(`                if(entity.${window.$upFirst(mainKey.name)} != null)`);
      insertMethod.add(`                {`);
      table.columns.forEach((col) => {
        if (col.dataType == "createId") {
          insertMethod.add(`                    entity.${window.$upFirst(col.name)} = this.GetUserId();`);
        }
        if (col.dataType == "createName") {
          insertMethod.add(`                    entity.${window.$upFirst(col.name)} = this.GetUserName();`);
        }
        if (col.dataType == "createTime") {
          insertMethod.add(`                    entity.${window.$upFirst(col.name)} = DateTime.Now;`);
        }
      });
      insertMethod.add(`                }`);
    }

    table.columns.forEach((col) => {
      if (col.dataType == "modifyId") {
        updateMethod.add(`                entity.${window.$upFirst(col.name)} = this.GetUserId();`);
      }
      if (col.dataType == "modifyName") {
        updateMethod.add(`                entity.${window.$upFirst(col.name)} = this.GetUserName();`);
      }
      if (col.dataType == "modifyTime") {
        updateMethod.add(`                entity.${window.$upFirst(col.name)} = DateTime.Now;`);
      }
    });
    updateMethod.add(`                entity.${window.$upFirst(mainKey.name)} = keyValue;`);
  }

  strCode = insertMethod.writeTo(strCode, "InsertMethod");
  insertMethod = null;

  strCode = updateMethod.writeTo(strCode, "UpdateMethod");
  updateMethod = null;

  strCode = strCode.replace(/@PkIsNull/g, `${pkIsNull}`);
  strCode = strCode.replace(/@PkType/g, `${pkCsType}`);
  strCode = strCode.replace(/@Des/g, `${setting.des}`);

  strCode = strCode.replace(/@DBCode/g, setting.dbCode == "saas" ? "" : `"${setting.dbCode}"`);
  strCode = strCode.replace(/@MainTableEntity/g, window.$upFirst(table.className) + "Entity");
  return strCode;
};
